package com.share.common.rabbit.service;

import com.alibaba.fastjson2.JSON;
import com.share.common.core.utils.uuid.UUID;
import com.share.common.rabbit.constant.MqConst;
import com.share.common.rabbit.domain.SelfCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * rabbitmq封装工具类
 */
@Service
@Slf4j
public class RabbitService {

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 发送消息到队列
     *
     * @param exchange   交换机
     * @param routingKey 交换机与队列绑定的key
     * @param message    消息
     */
    public boolean sendMessage(String exchange, String routingKey, Object message) {
        //将消息数据封装为 自定义相关消息对象 CorrelationData
        //包含业务数据本身，交换器名称，路由键，队列类型，延迟时间,重试次数
        SelfCorrelationData selfCorrelationData = new SelfCorrelationData();

        //设置消息id 唯一标识 并将uuid中的 - 删去
        String uuid = "mq:" + UUID.randomUUID().toString().replaceAll("-", "");
        selfCorrelationData.setId(uuid);
        //消息数据
        selfCorrelationData.setMessage(message);
        //交换机名
        selfCorrelationData.setExchange(exchange);
        //交换机 队列 routing key
        selfCorrelationData.setRoutingKey(routingKey);

        //发送消息到mq selfCorrelationData参数用于存储消息相关数据（如uuid等） 处理完成后的回调（成功或失败）
        rabbitTemplate.convertAndSend(exchange, routingKey, message, selfCorrelationData);

        //将消息数据存入redis key：消息的uuid value：消息的json格式的字符串 设置过期时间为10min
        //用于保证消息可靠性，如果Rabbit服务下线了，可通过redis恢复数据，
        // 或者当未收到确认消息时，可从redis中取出数据进行重发
        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(selfCorrelationData), 10, TimeUnit.MINUTES);

        return true;
    }

    /**
     * 发送延迟消息方法
     *
     * @param exchange   交换机
     * @param routingKey 路由键
     * @param message    消息数据
     * @param delayTime  延迟时间，单位为：秒
     */
    public boolean sendDealyMessage(String exchange, String routingKey, String message, int delayTime) {
        //1.创建自定义相关消息对象-包含业务数据本身，交换器名称，路由键，队列类型，延迟时间,重试次数
        SelfCorrelationData correlationData = new SelfCorrelationData();

        //消息id
        String uuid = "mq:" + UUID.randomUUID().toString().replaceAll("-", "");
        correlationData.setId(uuid);
        //消息数据
        correlationData.setMessage(message);
        //交换机
        correlationData.setExchange(exchange);
        //routing key
        correlationData.setRoutingKey(routingKey);
        //需要 延迟
        correlationData.setDelay(true);
        //延迟时间
        correlationData.setDelayTime(delayTime);

        //2.将相关消息封装到发送消息方法中
        rabbitTemplate.convertAndSend(
                exchange,
                routingKey,
                message, //原始消息内容
                msg -> {  //消息后置处理器，用于修改消息属性
                    msg.getMessageProperties().setDelay(delayTime * 1000); //设置消息延迟发送时间
                    return msg;
                },
                correlationData);


        //3.将相关消息存入Redis  Key：UUID  相关消息对象  10 分钟
        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData), 10, TimeUnit.MINUTES);
        return true;

    }
}
